# -*- coding: utf-8 -*-
"""
core/代码应用/git_manager.py

Git版本控制模块。
封装了常用的Git操作，如初始化仓库、add、commit、push（预留）。
"""

import os
import subprocess
from core.utils import logger

class GitManager:
    """
    Git管理器类，用于在指定的代码库目录执行Git操作。
    """
    def __init__(self, repo_path):
        """
        初始化Git管理器。

        参数:
            repo_path (str): Git仓库的本地路径。
        """
        self.repo_path = repo_path
        if not os.path.isdir(self.repo_path):
            logger.warning(f"Git仓库路径不存在: {self.repo_path}。某些Git操作可能失败或需要先初始化。")

    def _run_git_command(self, command_parts):
        """
        在仓库路径下执行Git命令。

        参数:
            command_parts (list): Git命令及其参数的列表，例如 ["status"], ["add", "."].

        返回:
            tuple: (return_code, stdout, stderr)
        """
        try:
            process = subprocess.Popen(
                ["git"] + command_parts,
                cwd=self.repo_path,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True, # Python 3.7+ for text=True
                encoding="utf-8" # 尝试指定编码
            )
            stdout, stderr = process.communicate(timeout=60) # 60秒超时
            logger.debug(f"Git command: git {" ".join(command_parts)}")
            logger.debug(f"Git stdout: {stdout.strip()}")
            if stderr.strip():
                logger.warning(f"Git stderr: {stderr.strip()}")
            return process.returncode, stdout, stderr
        except FileNotFoundError:
            logger.error("Git命令未找到。请确保Git已安装并配置在系统PATH中。")
            return -1, "", "Git command not found."
        except subprocess.TimeoutExpired:
            logger.error(f"Git命令执行超时: git {" ".join(command_parts)}")
            process.kill()
            return -1, "", "Git command timed out."
        except Exception as e:
            logger.error(f"执行Git命令时发生未知错误: git {" ".join(command_parts)}. Error: {e}")
            return -1, "", str(e)

    def is_git_repo(self):
        """
        检查当前路径是否是一个Git仓库。
        """
        # .git 目录通常在仓库根目录
        # 更可靠的方式是运行一个如 `git rev-parse --is-inside-work-tree` 的命令
        if not os.path.isdir(os.path.join(self.repo_path, ".git")):
             # 尝试运行命令确认
            ret_code, _, _ = self._run_git_command(["rev-parse", "--is-inside-work-tree"])
            return ret_code == 0
        return True

    def init_repo(self):
        """
        在指定路径初始化新的Git仓库 (如果尚不存在)。
        """
        if not os.path.exists(self.repo_path):
            try:
                os.makedirs(self.repo_path)
                logger.info(f"创建目录: {self.repo_path}")
            except Exception as e:
                logger.error(f"创建仓库目录 {self.repo_path} 失败: {e}")
                return False
                
        if self.is_git_repo():
            logger.info(f"目录 {self.repo_path} 已经是Git仓库。")
            return True
        
        logger.info(f"在 {self.repo_path} 初始化Git仓库...")
        ret_code, stdout, stderr = self._run_git_command(["init"])
        if ret_code == 0:
            logger.info(f"Git仓库初始化成功: {self.repo_path}")
            # 初始提交通常需要配置用户名和邮箱
            # self.set_user_config("Your Name", "you@example.com") # 可选
            return True
        else:
            logger.error(f"Git仓库初始化失败。Stdout: {stdout}, Stderr: {stderr}")
            return False

    def set_user_config(self, user_name="AutoGen System", user_email="autogen@example.com"):
        """
        为当前仓库设置用户名和邮箱，这对于首次提交是必需的。
        """
        logger.info(f"为仓库 {self.repo_path} 设置Git用户信息: Name={user_name}, Email={user_email}")
        ret_name, _, err_name = self._run_git_command(["config", "user.name", user_name])
        ret_email, _, err_email = self._run_git_command(["config", "user.email", user_email])
        if ret_name != 0 or ret_email != 0:
            logger.warning(f"设置Git用户信息可能失败。Name_err: {err_name}, Email_err: {err_email}")
            return False
        return True

    def add_files(self, files_to_add=["."]):
        """
        将文件添加到Git暂存区。

        参数:
            files_to_add (list): 要添加的文件列表。默认为["."] (添加所有更改)。
        """
        if not isinstance(files_to_add, list):
            files_to_add = [files_to_add]
        
        logger.info(f"向Git暂存区添加文件: {files_to_add} ...")
        command = ["add"] + files_to_add
        ret_code, stdout, stderr = self._run_git_command(command)
        if ret_code == 0:
            logger.info(f"文件 {files_to_add} 添加到暂存区成功。")
            return True
        else:
            logger.error(f"添加文件 {files_to_add} 到暂存区失败。Stdout: {stdout}, Stderr: {stderr}")
            return False

    def commit_changes(self, commit_message):
        """
        提交暂存区的更改。

        参数:
            commit_message (str): 提交信息。
        """
        logger.info(f"提交Git更改，信息: 	"{commit_message}	" ...")
        # 检查是否有用户信息配置，否则首次提交会失败
        ret_name, _, _ = self._run_git_command(["config", "--local", "user.name"])
        ret_email, _, _ = self._run_git_command(["config", "--local", "user.email"])
        if ret_name != 0 or ret_email != 0:
            logger.warning("Git user.name 或 user.email 未配置。尝试设置默认值。")
            if not self.set_user_config(): # 设置默认值
                 logger.error("设置默认Git用户信息失败，提交可能会失败。")

        command = ["commit", "-m", commit_message]
        ret_code, stdout, stderr = self._run_git_command(command)
        if ret_code == 0:
            logger.info(f"Git提交成功。信息: 	"{commit_message}	" ")
            return True
        elif "nothing to commit" in stdout or "nothing to commit" in stderr:
            logger.info("没有需要提交的更改。")
            return True # 认为没有更改也算成功
        else:
            logger.error(f"Git提交失败。信息: 	"{commit_message}	". Stdout: {stdout}, Stderr: {stderr}")
            return False

    def push_changes(self, remote_name="origin", branch_name="main"):
        """
        将本地提交推送到远程仓库 (预留功能)。
        实际使用时需要配置远程仓库地址和认证。

        参数:
            remote_name (str): 远程仓库名称。
            branch_name (str): 要推送的分支名称。
        """
        logger.info(f"准备将更改推送到远程仓库 {remote_name}/{branch_name} (此功能为预留，当前不执行实际推送)。")
        # 实际推送命令: self._run_git_command(["push", remote_name, branch_name])
        # 需要处理认证等问题，例如使用SSH密钥或HTTPS Token
        logger.warning("实际的 `git push` 操作未实现。请手动配置和执行推送。")
        return True # 模拟成功

if __name__ == "__main__":
    project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
    mock_repo_dir = os.path.join(project_root, "data", "output", "mock_git_repo_test")

    # 清理并创建测试仓库目录
    if os.path.exists(mock_repo_dir):
        import shutil
        # 如果是Windows，直接删除.git目录可能因权限问题失败，需要更复杂的清理
        # 对于Linux/macOS， shutil.rmtree 应该可以
        try:
            # 确保有权限删除.git内的文件
            for root, dirs, files in os.walk(os.path.join(mock_repo_dir, ".git")):
                for name in files:
                    os.chmod(os.path.join(root, name), 0o777)
                for name in dirs:
                    os.chmod(os.path.join(root, name), 0o777)
            shutil.rmtree(mock_repo_dir)
        except Exception as e_rm:
            logger.error(f"清理旧的mock_repo_dir失败: {e_rm}")
            pass # 继续尝试创建
            
    os.makedirs(mock_repo_dir, exist_ok=True)
    logger.info(f"测试Git仓库目录: {mock_repo_dir}")

    git_manager = GitManager(repo_path=mock_repo_dir)

    logger.info("\n--- 测试Git仓库初始化 ---")
    if git_manager.init_repo():
        logger.info("仓库初始化成功。")
        assert git_manager.is_git_repo() == True
        
        # 设置用户信息 (对于某些Git版本，首次提交前必须设置)
        git_manager.set_user_config("Test User", "test@example.com")

        logger.info("\n--- 测试Git添加和提交 ---")
        # 创建一个测试文件
        test_file_path = os.path.join(mock_repo_dir, "test_file.txt")
        with open(test_file_path, "w", encoding="utf-8") as f:
            f.write("这是第一次提交的内容。\n")
        logger.info(f"创建了测试文件: {test_file_path}")

        if git_manager.add_files(["test_file.txt"]):
            logger.info("文件添加成功。")
            if git_manager.commit_changes("首次提交: 添加 test_file.txt"):
                logger.info("首次提交成功。")
            else:
                logger.error("首次提交失败。")
        else:
            logger.error("文件添加失败。")

        # 修改文件并再次提交
        with open(test_file_path, "a", encoding="utf-8") as f:
            f.write("这是第二次提交的新增内容。\n")
        logger.info(f"修改了测试文件: {test_file_path}")

        if git_manager.add_files(["test_file.txt"]): # 或者用 [".
